<?php

/////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 Point Clark Networks.
//
///////////////////////////////////////////////////////////////////////////////
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////

/**
 * Shell execution class.
 *
 * @package Api
 * @author {@link http://www.pointclark.net/ Point Clark Networks}
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @copyright Copyright 2006, Point Clark Networks
 */

///////////////////////////////////////////////////////////////////////////////
// D E P E N D E N C I E S
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// C L A S S
///////////////////////////////////////////////////////////////////////////////

/**
 * Wrapper for running shell commands.
 *
 * @package Api
 * @author {@link http://www.pointclark.net/ Point Clark Networks}
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @copyright Copyright 2006, Point Clark Networks
 */

class CShellExec
{
	///////////////////////////////////////////////////////////////////////////////
	// M E M B E R S
	///////////////////////////////////////////////////////////////////////////////

	protected $output = array();

	const CMD_SUEXEC = "/usr/bin/sudo";

	///////////////////////////////////////////////////////////////////////////////
	// M E T H O D S
	///////////////////////////////////////////////////////////////////////////////

	/**
	 * ShellExec constructor.
	 */

	public function __construct()
	{
	}

	/**
	 * Executes the command.
	 *
	 * Excecute options are:
	 * - escape: scrub command line arguments for naught characters (default true)
	 * - log: specify a log file (default /dev/null)
	 * - env: environment variables (default null)
	 * - background: run command in background (default false)
	 * - stdin: write arguments to stdin (default false)
	 * 
	 * @param string $command command to excecute
	 * @param string $arguments command arguments
	 * @param boolean $superuser super user flag
	 * @param array $options extra execute options specified above
	 * @return int $retval command return code
	 */

	public function Execute($command, $arguments, $superuser = false, $options = null)
	{

		$this->output = array();

		if (isset($options['escape']) && $options['escape']) {
			$command = escapeshellcmd($command);
			$arguments = escapeshellcmd($arguments);
		}

		if (strlen($arguments))
			$exe = $command . " " . $arguments;
		else
			$exe = $command;

		if ($superuser)
			$exe = self::CMD_SUEXEC . " " . $exe;

		if (isset($options['env']))
			$exe = $options['env'] . " $exe";

		// If set to background, output *must* be redirected to 
		// either a log or /dev/null

		if (isset($options['log']))
			$exe .= " >>" . "" . $options['log'];
		else if (isset($options['devnull']) && $options['devnull'])
			$exe .= " >/dev/null";
		else if(isset($options['exe'])) $exe .= " >".$options['exe'];

		$exe .= " 2>&1";

		if (isset($options['background']) && $options['background'])
			$exe .= " &";

		$retval = null;

		if (isset($options['stdin'])) {
			$ph = popen($exe, "w");

			if (strlen($options['stdin']))
				fwrite($ph, $options['stdin']);

			$retval = pclose($ph);
		} else {
			exec($exe, $this->output, $retval);
		}

		return $retval;
	}

	/* 
	 *@brief: 执行一个命令并检测其返回结果 如果返回的结果中包含参数$pattern的内容时 认为该命令执行成功 
	 *@param stirng $command  a executing command 
	 *@param array or string  $pattern  
	 *@param string $savePath  store filepath after exec command, permit to be empty 
	 *@options array, eg: $options['background'] = true; 
	 *@param array $regs  store matching result 
	 *@return 0 -- success, < 0 failure 
	 */
	function ExecuteMatch($command, $pattern, $savePath = null, $options = null, &$regs = null)
	{
		if($command == "") {
			return -1;
		}

		if($savePath == "") {
			$savePath = "/tmp/netpower-" . date("YmdHis") . "-" . mt_rand(); 
		}
		$command .= " > $savePath";
		$retval = $this->Execute($command, "", true, $options);
		if($retval != 0) {
			$this->Execute("rm -f $savePath", "", true);
			return -2;
		}
		
		$tmpPath = "/tmp/netpower-" . date("YmdHis") . "-" . mt_rand();
		if(is_array($pattern)) {
			$commanda = "cat $savePath";
			foreach($pattern as $pa) {
				$commanda .= " |grep -i \"$pa\"";
			}
			$commanda .= " > $tmpPath";
		} else {
			$commanda = "cat $savePath |grep -i \"$pattern\" > $tmpPath";
		}
		$retval = $this->Execute($commanda, "", true);
		if($retval != 0){
			$this->Execute("rm -f $savePath", "", true);
			$this->Execute("rm -f $tmpPath", "", true);
			return -3;  //if don't get any text when grep, here return
		}

		if($regs == null)
			$regs = array();
		$regs = file($tmpPath);
		$this->Execute("rm -f $savePath", "", true);
		$this->Execute("rm -f $tmpPath", "", true);
		if(count($regs) > 0)
			return 0;
		else 
			return -4;
	}

	/**
	 * Returns output from executed command.
	 *
	 * @return array command output as an array of strings
	 */

	public function GetOutput()
	{
		return $this->output;
	}

	/**
	 * Returns first output line.
	 *
	 * This method is useful for capturing simple command output (including errors).
	 *
	 * @return string first output line
	 */

	public function GetFirstOutputLine()
	{
		if (isset($this->output[0]))
			return $this->output[0];
		else
			return "";
	}

	/**
	 * Returns last output line.
	 *
	 * This method is useful for capturing the last line of output (including errors).
	 *
	 * @return string last output line
	 */

	public function GetLastOutputLine()
	{
		if (isset($this->output[sizeof($this->output) - 1]))
			return $this->output[sizeof($this->output) - 1];
		else
			return "";
	}

	/**
	 * @access private
	 */

	public function __destruct()
	{
	}
}

// vim: syntax=php ts=4
